/*
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2004-2007 Intel Corporation. All Rights Reserved.
//
//     Intel Integrated Performance Primitives AAC Encode Sample for Windows*
//
//  By downloading and installing this sample, you hereby agree that the
//  accompanying Materials are being provided to you under the terms and
//  conditions of the End User License Agreement for the Intel Integrated
//  Performance Primitives product previously accepted by you. Please refer
//  to the file ippEULA.rtf or ippEULA.txt located in the root directory of your Intel IPP
//  product installation for more information.
//
//  MPEG-4 and AAC are international standards promoted by ISO, IEC, ITU, ETSI
//  and other organizations. Implementations of these standards, or the standard
//  enabled platforms may require licenses from various entities, including
//  Intel Corporation.
//
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_AAC_INT_AUDIO_ENCODER)

#include <stdio.h>
#include <math.h>
#include "ipps.h"
#include "ippac.h"
#include "aac_enc_psychoacoustic_int.h"
#include "aac_sfb_tables.h"

#define FIND_NORM_SHIFT_16S(pSrc, len, shift) \
{                                             \
  Ipp16s _min0, _max0;                        \
  Ipp32s _min, _max;                          \
                                              \
  ippsMinMax_16s(pSrc, len, &_min0, &_max0);  \
                                              \
  _min = -((Ipp32s)_min0);                    \
  _max = _max0;                               \
                                              \
  if (_min > _max) {                          \
    _max = _min - 1;                          \
  }                                           \
                                              \
  shift = 0;                                  \
                                              \
  if (_max > 0) {                             \
    while (_max <= 16383) {                   \
      _max = _max << 1;                       \
      shift++;                                \
    }                                         \
  }                                           \
}

/****************************************************************************/

static void aaciencPsy_long_window(sPsychoacousticBlock* pBlock,
                                   sPsychoacousticBlockCom* pBlockCom,
                                   Ipp32s* ms_pwr,
                                   Ipp32s* ms_pwr_Scalef,
                                   Ipp32s* PE,
                                   Ipp32s ch,
                                   Ipp32s ind)
{
__ALIGN Ipp32s  rsqr_long[1024];
__ALIGN Ipp16s  sw[N_LONG];
__ALIGN Ipp16s  abs_sw[N_LONG];
__ALIGN Ipp16s  fft_line[__ALIGNED(2*N_LONG+2)];
__ALIGN Ipp32s  e_b[MAX_PPT_LONG];
__ALIGN Ipp32s  c_b[MAX_PPT_LONG];
__ALIGN Ipp32s  ecb[MAX_PPT_LONG];
__ALIGN Ipp32s  ct[MAX_PPT_LONG];
__ALIGN Ipp32s  tmp_ecb[MAX_PPT_LONG];
__ALIGN Ipp32s  tmp_ct[MAX_PPT_LONG];
__ALIGN Ipp32s  ecb_h_limit[MAX_PPT_LONG];
__ALIGN Ipp32s  ecb_l_limit[MAX_PPT_LONG];
__ALIGN Ipp16s  c_w[1024];
__ALIGN Ipp16s  tmp_ln[MAX_PPT_LONG];
__ALIGN Ipp16s  tmp_ln0[MAX_PPT_LONG];
__ALIGN Ipp16s  tmp_ln1[MAX_PPT_LONG];
__ALIGN Ipp16s  tmp[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  tmp0[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  tmp1[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  tmp2[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  tmp3[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  tmp4[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  tmp5[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  denum[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  r_pred[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  re_pred[NUM_UNPRED_LINES_LONG];
__ALIGN Ipp16s  im_pred[NUM_UNPRED_LINES_LONG];
  Ipp16s        *r, *r_prev, *r_prev_prev;
  Ipp16s        *re, *re_prev, *re_prev_prev;
  Ipp16s        *im, *im_prev, *im_prev_prev;
  Ipp16s        *tmp_dst[2];
  Ipp32s        *nb,*nb_l;
  Ipp32s        b, scaleFactor;
  Ipp32s        sum;
  Ipp32s        shift0, shift1, shift;
  Ipp32s        rScaleFactor, r_prevScaleFactor;
  Ipp32s        r_prev_prevScaleFactor, r_predScaleFactor;
  Ipp32s        nb_ScaleFactor, nb_lScaleFactor;
  Ipp32s        num_ptt_long = pBlockCom->longWindow->num_ptt;
  Ipp32s        rsqr_longScale;

  ippsMul_16s_Sfs((Ipp16s*)pBlockCom->input_data[ch][0], AACI_HANN_long,
                    sw, pBlockCom->iblen_long, 15);
  ippsMul_16s_Sfs((Ipp16s*)pBlockCom->input_data[ch][1],
                    &AACI_HANN_long[pBlockCom->iblen_long],
                    &sw[1024], pBlockCom->iblen_long, 15);
  ippsAbs_16s(sw, abs_sw, 2 * pBlockCom->iblen_long);
  ippsSum_16s32s_Sfs(abs_sw, 2 * pBlockCom->iblen_long, &sum, 0);

  scaleFactor = 0;
  if (sum != 0) {
    if (sum > 32768) {
      while (sum > 32768) {
        sum >>= 1;
        scaleFactor++;
      }
    } else {
      while (sum <= 16384) {
        sum *= 2;
        scaleFactor--;
      }
    }
  }

  ippsFFTFwd_RToCCS_16s_Sfs(sw, fft_line, pBlockCom->pFFTSpecLong,
                            scaleFactor, pBlockCom->pBuffer);

  r            = (Ipp16s*)pBlock->r[ind][pBlockCom->current_f_r_index];
  re           = (Ipp16s*)pBlock->re[ind][pBlockCom->current_f_r_index];
  im           = (Ipp16s*)pBlock->im[ind][pBlockCom->current_f_r_index];

  ippsMagnitude_16sc_Sfs((Ipp16sc *)fft_line, r, pBlockCom->iblen_long, 1);

  if (ind) {
    ippsSum_16s32s_Sfs(r, 1024, ms_pwr, 0);
    *ms_pwr_Scalef = scaleFactor + 1;
  }

  ippsThreshold_LT_16s_I(r, pBlockCom->iblen_long, 1);

  tmp_dst[0] = re;
  tmp_dst[1] = im;

  ippsDeinterleave_16s(fft_line, 2, NUM_UNPRED_LINES_LONG, tmp_dst);
  /* re and im in Q15 */
  ippsDiv_16s_ISfs(r, re, NUM_UNPRED_LINES_LONG, -14);
  ippsDiv_16s_ISfs(r, im, NUM_UNPRED_LINES_LONG, -14);

  FIND_NORM_SHIFT_16S(r, pBlockCom->iblen_long, shift)
  ippsLShiftC_16s_I(shift, r, pBlockCom->iblen_long);
  rScaleFactor = scaleFactor + 1 - shift;

  pBlock->rScaleFactor[ind][pBlockCom->current_f_r_index] = rScaleFactor;

  r_prev       = (Ipp16s*)pBlock->r[ind][pBlockCom->prev_f_r_index];
  re_prev      = (Ipp16s*)pBlock->re[ind][pBlockCom->prev_f_r_index];
  im_prev      = (Ipp16s*)pBlock->im[ind][pBlockCom->prev_f_r_index];

  r_prevScaleFactor = pBlock->rScaleFactor[ind][pBlockCom->prev_f_r_index];

  r_prev_prev  = (Ipp16s*)pBlock->r[ind][pBlockCom->prev_prev_f_r_index];
  re_prev_prev = (Ipp16s*)pBlock->re[ind][pBlockCom->prev_prev_f_r_index];
  im_prev_prev = (Ipp16s*)pBlock->im[ind][pBlockCom->prev_prev_f_r_index];

  r_prev_prevScaleFactor = pBlock->rScaleFactor[ind][pBlockCom->prev_prev_f_r_index];

  /* Calculate the unpredictability measure c(w)                */
  /* Some transformations:                                      */
  /* re((2*r_prev-r_prev_prev)*exp(-j(2*f_prev-f_prev_prev))) = */
  /* (2*r_prev-r_prev_prev)*                                    */
  /* (2*im_prev_prev*re_prev*im_prev +                          */
  /* re_prev_prev*(re_prev*re_prev-im_prev*im_prev))            */
  /*                                                            */
  /* im((2*r_prev-r_prev_prev)*exp(-j(2*f_prev-f_prev_prev))) = */
  /* (2*r_prev-r_prev_prev) *                                   */
  /* (2*re_prev_prev*re_prev*im_prev -                          */
  /* im_prev_prev*(re_prev*re_prev-im_prev*im_prev))            */
  /*                                                            */
  /* where re_prev_prev = cos(prev_prev_f),                     */
  /*       im_prev_prev = sin(prev_prev_f),                     */
  /*       re_prev = cos(prev_prev_f),                          */
  /*       im_prev = sin(prev_prev_f)                           */

  /* r_pred = (2*r_prev-r_prev_prev) */
  r_predScaleFactor = r_prevScaleFactor + 1;
  if (r_prev_prevScaleFactor > r_predScaleFactor) {
    shift = r_prev_prevScaleFactor - r_predScaleFactor;
    if (shift > 16) shift = 16;
    ippsRShiftC_16s(r_prev, shift, tmp0, NUM_UNPRED_LINES_LONG);
    ippsSub_16s_Sfs(r_prev_prev, tmp0, r_pred, NUM_UNPRED_LINES_LONG, 1);
    r_predScaleFactor = r_prev_prevScaleFactor + 1;
  } else if (r_prev_prevScaleFactor < r_predScaleFactor) {
    shift = r_predScaleFactor - r_prev_prevScaleFactor;
    if (shift > 16) shift = 16;
    ippsRShiftC_16s(r_prev_prev, shift, tmp0,NUM_UNPRED_LINES_LONG);
    ippsSub_16s_Sfs(tmp0, r_prev, r_pred, NUM_UNPRED_LINES_LONG, 1);
    r_predScaleFactor++;
  } else {
    ippsSub_16s_Sfs(r_prev_prev, r_prev, r_pred, NUM_UNPRED_LINES_LONG, 1);
    r_predScaleFactor++;
  }

  /* tmp1 = 2*re_prev*im_prev (in Q14) */
  ippsMul_16s_Sfs(re_prev, im_prev, tmp1, NUM_UNPRED_LINES_LONG, 15);

  /* tmp2 = re_prev*re_prev-im_prev*im_prev (in Q14)*/
  ippsMul_16s_Sfs(re_prev, re_prev, tmp, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(im_prev, im_prev, tmp2, NUM_UNPRED_LINES_LONG, 15);
  ippsSub_16s_ISfs(tmp, tmp2,  NUM_UNPRED_LINES_LONG, 1);

  /* im_prev_prev * tmp1 + re_prev_prev * tmp2 (in Q13)*/
  ippsMul_16s_Sfs(im_prev_prev, tmp1, re_pred, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(re_prev_prev, tmp2, tmp, NUM_UNPRED_LINES_LONG, 15);
  ippsAdd_16s_ISfs(tmp, re_pred, NUM_UNPRED_LINES_LONG, 1);

  /* re_prev_prev * tmp1 - im_prev_prev * tmp2 (in Q13)*/
  ippsMul_16s_Sfs(re_prev_prev, tmp1, im_pred, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(im_prev_prev, tmp2, tmp, NUM_UNPRED_LINES_LONG, 15);
  ippsSub_16s_ISfs(tmp, im_pred, NUM_UNPRED_LINES_LONG, 1);

  ippsAbs_16s(r_pred, denum,  NUM_UNPRED_LINES_LONG);

  /* denumScaleFactor = (shift0 == 0) ? r_predScaleFactor + 1 : rScaleFactor + 1 */
  if (r_predScaleFactor > rScaleFactor) {
    shift0 = 0;
    shift1 = r_predScaleFactor - rScaleFactor;
    if (shift1 > 16) shift1 = 16;
    ippsRShiftC_16s(r, shift1, tmp0, NUM_UNPRED_LINES_LONG);
    ippsAdd_16s_ISfs(tmp0, denum, NUM_UNPRED_LINES_LONG, 1);
  } else if (r_predScaleFactor < rScaleFactor) {
    shift0 = rScaleFactor - r_predScaleFactor;
    shift1 = 0;
    if (shift0 > 16) shift0 = 16;
    ippsRShiftC_16s(denum, shift0, tmp0, NUM_UNPRED_LINES_LONG);
    ippsAdd_16s_Sfs(r, tmp0, denum, NUM_UNPRED_LINES_LONG, 1);
  } else {
    shift0 = 0;
    shift1 = 0;
    ippsAdd_16s_ISfs(r, denum, NUM_UNPRED_LINES_LONG, 1);
  }

  /* tmp0 in Q15 */
  ippsDiv_16s_Sfs(denum, r_pred, tmp0, NUM_UNPRED_LINES_LONG, -14 + shift0);
  /* tmp1 in Q15 */
  ippsDiv_16s_Sfs(denum, r, tmp1, NUM_UNPRED_LINES_LONG, -14 + shift1);

  /* tmp2 in Q13 */
  ippsMul_16s_Sfs(tmp0, re_pred, tmp2, NUM_UNPRED_LINES_LONG, 15);
  /* tmp3 in Q13 */
  ippsMul_16s_Sfs(tmp0, im_pred, tmp3, NUM_UNPRED_LINES_LONG, 15);
  /* tmp4 in Q13 */
  ippsMul_16s_Sfs(tmp1, re, tmp4, NUM_UNPRED_LINES_LONG, 17);
  /* tmp5 in Q13 */
  ippsMul_16s_Sfs(tmp1, im, tmp5, NUM_UNPRED_LINES_LONG, 17);
  /* tmp0 in Q12 */
  ippsSub_16s_Sfs(tmp2, tmp4, tmp0, NUM_UNPRED_LINES_LONG, 1);
  /* tmp1 in Q12 */
  ippsSub_16s_Sfs(tmp3, tmp5, tmp1, NUM_UNPRED_LINES_LONG, 1);
  /* c_w in Q15 */
  ippsMagnitude_16s_Sfs(tmp0, tmp1, c_w, NUM_UNPRED_LINES_LONG, -3);

  ippsSet_16s(13107, &c_w[ NUM_UNPRED_LINES_LONG],
               pBlockCom->iblen_long -  NUM_UNPRED_LINES_LONG);

  ippsMul_16s32s_Sfs((Ipp16s*)r, (Ipp16s*)r, rsqr_long, pBlockCom->iblen_long, 0);
  rsqr_longScale = 2 * rScaleFactor;

  for (b = 0; b < num_ptt_long; b++) {
    Ipp32s *tmp_rsqr = &rsqr_long[pBlockCom->longWindow->w_low[b]];
    Ipp16s *tmp_c_w = (Ipp16s*)&c_w[pBlockCom->longWindow->w_low[b]];
    Ipp32s len = pBlockCom->longWindow->w_width[b];

    ippsSum_32s_Sfs(tmp_rsqr, len, &e_b[b], pBlockCom->longScale - 1);
    ippsDotProd_16s32s32s_Sfs(tmp_c_w, tmp_rsqr, len,
                              &c_b[b], pBlockCom->longScale + 14);
  }

  nb   = (Ipp32s *)pBlock->nb_long[ind][pBlockCom->nb_curr_index];
  nb_l = (Ipp32s *)pBlock->nb_long[ind][pBlockCom->nb_prev_index];

  PE[0] = 0;

  for (b = 0; b < num_ptt_long; b++) {
    Ipp16s *tmp_ptr = (Ipp16s*)pBlockCom->sprdngf_long +
                               b * num_ptt_long;

    ippsDotProd_16s32s32s_Sfs(tmp_ptr, e_b, num_ptt_long, &ecb[b], 15);
    ippsDotProd_16s32s32s_Sfs(tmp_ptr, c_b, num_ptt_long, &ct[b], 15);
  }

  ippsMulC_32s_Sfs(ecb, 20219, tmp_ecb, num_ptt_long, 21);
  ippsMulC_32s_Sfs(ct, 17131, tmp_ct, num_ptt_long, 15);

  ippsAdd_32s_Sfs(tmp_ct, tmp_ecb, nb, num_ptt_long, 0);
  ippsMulC_32s_Sfs(ecb, 16462, ecb_h_limit, num_ptt_long, 16);
  ippsMulC_32s_Sfs(ecb, 16619, ecb_l_limit, num_ptt_long, 20);
  ippsMaxEvery_32s_I(ecb_l_limit, nb, num_ptt_long);
  ippsMinEvery_32s_I(ecb_h_limit, nb, num_ptt_long);

  /* instead of tmp_nb = MAX( pow(10.0,pBlock->qsthr_long[b]/10.0)/32767.0, */
  /*                         MIN(nb[b],2.0*nb_l[b]));                       */
  /* we use only tmp_nb = MIN(nb[b],2.0*nb_l[b]) yet                        */

  nb_ScaleFactor = rsqr_longScale + pBlockCom->longScale - 1;
  nb_lScaleFactor = pBlock->nb_longScaleFactor[ind];

  nb_lScaleFactor += 1;
  if (nb_lScaleFactor > nb_ScaleFactor) {
    shift = nb_lScaleFactor - nb_ScaleFactor;
    /* I'm using MulC here because LShiftC doesn't provide saturation */
    ippsMulC_32s_ISfs(1, nb_l, num_ptt_long, -shift);
  } else if (nb_lScaleFactor < nb_ScaleFactor) {
    shift = nb_ScaleFactor - nb_lScaleFactor;
    if (shift > 31) shift = 31;
    ippsRShiftC_32s_I(shift, nb_l, num_ptt_long);
  }

  ippsMinEvery_32s_I(nb, nb_l, num_ptt_long);
  ippsLn_32s16s_Sfs(nb_l, tmp_ln0, num_ptt_long, -10);

  pBlock->nb_longScaleFactor[ind] = nb_ScaleFactor;

  ippsLn_32s16s_Sfs(e_b, tmp_ln1, num_ptt_long, -10);
  ippsSub_16s_Sfs(tmp_ln0, tmp_ln1, tmp_ln, num_ptt_long, 1);
  FIND_NORM_SHIFT_16S(tmp_ln, num_ptt_long, shift)
  ippsMul_16s_ISfs(pBlockCom->longWindow->w_width, tmp_ln, num_ptt_long,
                   pBlockCom->longScale - shift);
  ippsSum_16s32s_Sfs(tmp_ln, num_ptt_long, PE,
                     9 - pBlockCom->longScale + shift);

  if (pBlockCom->ns_mode) {
    Ipp32s epart[MAX_SFB];
    Ipp32s npart[MAX_SFB];
    Ipp32s *smr;
    Ipp32s sb;

    for (sb = 0; sb < pBlockCom->num_sfb_long; sb++) {
      Ipp32s start = pBlockCom->aacenc_p2sb_l[sb].bu;
      Ipp32s end = pBlockCom->aacenc_p2sb_l[sb].bo;

      epart[sb] = (Ipp32s)((((Ipp64s)pBlockCom->aacenc_p2sb_l[sb].w1 * e_b[start]) >> 32) +
                           (((Ipp64s)pBlockCom->aacenc_p2sb_l[sb].w2 * e_b[end]) >> 32));

      npart[sb] = (Ipp32s)((((Ipp64s)pBlockCom->aacenc_p2sb_l[sb].w1 * nb[start]) >> 32) +
                           (((Ipp64s)pBlockCom->aacenc_p2sb_l[sb].w2 * nb[end]) >> 32));

      for (b = start + 1; b < end; b++) {
        epart[sb] += (e_b[b] >> 2);
        npart[sb] += (nb[b] >> 2);
      }
    }
    smr = (Ipp32s*)pBlock->smr_long[pBlockCom->nb_curr_index];
    ippsDiv_32s_Sfs(epart, npart, smr, pBlockCom->num_sfb_long, -21);
  }
}

/****************************************************************************/

static void aaciencPsy_short_window(sPsychoacousticBlock* pBlock,
                                    sPsychoacousticBlockCom* pBlockCom,
                                    Ipp32s* s_en,
                                    Ipp32s ch,
                                    Ipp32s ind)
{
__ALIGN Ipp16s  sw_short[8][__ALIGNED(N_SHORT)];
__ALIGN Ipp16s  abs_sw[N_SHORT];
__ALIGN Ipp16s  fft_line[__ALIGNED(2*128+2)];
  Ipp16s        *ptr_input_data;
  Ipp16s        *r;
  Ipp32s        win_counter;
  Ipp32s        scaleFactor[8], shift;
  Ipp32s        min_shift, maxScaleFactor;
  Ipp32s        sum;
__ALIGN Ipp32s  rsqr_short[128];
__ALIGN Ipp32s  e_b[MAX_PPT_SHORT];
__ALIGN Ipp32s  c_b[MAX_PPT_SHORT];
__ALIGN Ipp32s  ecb[MAX_PPT_SHORT];
__ALIGN Ipp32s  ct[MAX_PPT_SHORT];
__ALIGN Ipp32s  tmp_ecb[MAX_PPT_SHORT];
__ALIGN Ipp32s  tmp_ct[MAX_PPT_SHORT];
__ALIGN Ipp32s  ecb_h_limit[MAX_PPT_SHORT];
__ALIGN Ipp32s  ecb_l_limit[MAX_PPT_SHORT];
__ALIGN Ipp32s  nb[MAX_PPT_SHORT];
__ALIGN Ipp16s  c_w[128];
__ALIGN Ipp16s  tmp[128];
__ALIGN Ipp16s  tmp0[128];
__ALIGN Ipp16s  tmp1[128];
__ALIGN Ipp16s  tmp2[128];
__ALIGN Ipp16s  tmp3[128];
__ALIGN Ipp16s  tmp4[128];
__ALIGN Ipp16s  tmp5[128];
__ALIGN Ipp16s  denum[128];
__ALIGN Ipp16s  r_pred[128];
__ALIGN Ipp16s  re_pred[128];
__ALIGN Ipp16s  im_pred[128];
  Ipp32s        *rsqr;
  Ipp16s        *r_prev, *r_prev_prev;
  Ipp16s        *re, *re_prev, *re_prev_prev;
  Ipp16s        *im, *im_prev, *im_prev_prev;
  Ipp16s        *tmp_dst[2];
  Ipp32s        b;
  Ipp32s        shift0, shift1;
  Ipp32s        rScaleFactor, r_prevScaleFactor;
  Ipp32s        r_prev_prevScaleFactor, r_predScaleFactor;
  Ipp32s        rsqr_shortScale;
  Ipp32s        num_ptt_short = pBlockCom->shortWindow->num_ptt;

  ptr_input_data = (Ipp16s*)pBlockCom->input_data[ch][0] + 448;

  for (win_counter = 0; win_counter < 3; win_counter++) {
    ippsMul_16s_Sfs(ptr_input_data, AACI_HANN_short,
                    sw_short[win_counter],
                    2 * pBlockCom->iblen_short, 15);
    ptr_input_data += pBlockCom->iblen_short;
  }

  ippsMul_16s_Sfs((Ipp16s*)(pBlockCom->input_data[ch][0] + 832), AACI_HANN_short,
                  sw_short[3], 2 * pBlockCom->iblen_short - 64, 15);

  ippsMul_16s_Sfs((Ipp16s*)pBlockCom->input_data[ch][1],
                  &AACI_HANN_short[2 * pBlockCom->iblen_short - 64],
                  &sw_short[3][2 * pBlockCom->iblen_short - 64], 64, 15);

  ippsMul_16s_Sfs((Ipp16s*)(pBlockCom->input_data[ch][0] + 960), AACI_HANN_short,
                  sw_short[4], 64, 15);

  ippsMul_16s_Sfs((Ipp16s*)pBlockCom->input_data[ch][1], &AACI_HANN_short[64],
                  &sw_short[4][64], 2 * pBlockCom->iblen_short - 64, 15);

  ptr_input_data = (Ipp16s*)pBlockCom->input_data[ch][1] + 64;

  for (win_counter = 5; win_counter < 8; win_counter++) {
    ippsMul_16s_Sfs(ptr_input_data, AACI_HANN_short,
                    sw_short[win_counter],
                  2 * pBlockCom->iblen_short, 15);
    ptr_input_data += pBlockCom->iblen_short;
  }

  min_shift = 100;
  maxScaleFactor = -100;

  for (win_counter = 0; win_counter < 8; win_counter++) {
    ippsAbs_16s(sw_short[win_counter], abs_sw, 2 * pBlockCom->iblen_short);
    ippsSum_16s32s_Sfs(abs_sw, 2 * pBlockCom->iblen_short, &sum, 0);

    scaleFactor[win_counter] = 0;
    if (sum != 0) {
      if (sum > 32768) {
        while (sum > 32768) {
          sum >>= 1;
          scaleFactor[win_counter]++;
        }
      } else {
        while (sum <= 16384) {
          sum *= 2;
          scaleFactor[win_counter]--;
        }
      }
    }

    ippsFFTFwd_RToCCS_16s_Sfs(sw_short[win_counter],
                              fft_line, pBlockCom->pFFTSpecShort,
                              scaleFactor[win_counter],
                              pBlockCom->pBuffer);

    r = (Ipp16s*)pBlock->r_short[ind][pBlockCom->current_f_r_index][win_counter];

    ippsMagnitude_16sc_Sfs((Ipp16sc *)fft_line, r, pBlockCom->iblen_short, 1);
    ippsThreshold_LT_16s_I(r, pBlockCom->iblen_short, 1);


    FIND_NORM_SHIFT_16S(&r[(pBlockCom->iblen_short >> 2)],
                        pBlockCom->iblen_short - (pBlockCom->iblen_short >> 2),
                        shift)
    if (min_shift > shift) min_shift = shift;
    if (maxScaleFactor < scaleFactor[win_counter])
      maxScaleFactor = scaleFactor[win_counter];

    if (pBlockCom->ns_mode) {
      re           = (Ipp16s*)pBlock->re_short[ind][pBlockCom->current_f_r_index][win_counter];
      im           = (Ipp16s*)pBlock->im_short[ind][pBlockCom->current_f_r_index][win_counter];

      tmp_dst[0] = re;
      tmp_dst[1] = im;

      ippsDeinterleave_16s(fft_line, 2, pBlockCom->iblen_short, tmp_dst);

      ippsDiv_16s_ISfs(r, re, pBlockCom->iblen_short, -14);
      ippsDiv_16s_ISfs(r, im, pBlockCom->iblen_short, -14);
    }
  }

  for (win_counter = 0; win_counter < 8; win_counter++) {

    r = (Ipp16s*)pBlock->r_short[ind][pBlockCom->current_f_r_index][win_counter];

    /* The scalefactor 12 - (2*shift+1) is calculated from max value to multiplay. */
    /* This value less than                                                        */
    /* (pBlockCom->iblen_short - (pBlockCom->iblen_short >> 2)) * 25 < 96 * 25 = 2400    */
    /* The value 25 is used in comparison (Psychoacoustic module)                  */
    ippsDotProd_16s32s_Sfs(&r[(pBlockCom->iblen_short >> 2)],
                           &r[(pBlockCom->iblen_short >> 2)],
                           pBlockCom->iblen_short - (pBlockCom->iblen_short >> 2),
                           &s_en[win_counter],
                           12 + 2 * (maxScaleFactor- scaleFactor[win_counter])
                           - (2*min_shift+1));

    if (pBlockCom->ns_mode) {
      Ipp32s epart[MAX_SFB];
      Ipp32s npart[MAX_SFB];
      Ipp32s *smr;
      Ipp32s sb;

      re           = (Ipp16s*)pBlock->re_short[ind][pBlockCom->current_f_r_index][win_counter];
      im           = (Ipp16s*)pBlock->im_short[ind][pBlockCom->current_f_r_index][win_counter];

      FIND_NORM_SHIFT_16S(r, pBlockCom->iblen_short, shift)
      ippsLShiftC_16s_I(shift, r, pBlockCom->iblen_short);
      rScaleFactor = scaleFactor[win_counter] + 1 - shift;

      pBlock->rScaleFactorShort[ind][pBlockCom->current_f_r_index][win_counter] =
              rScaleFactor;

      r_prev       = (Ipp16s*)pBlock->r_short[ind][pBlockCom->prev_f_r_index][win_counter];
      re_prev      = (Ipp16s*)pBlock->re_short[ind][pBlockCom->prev_f_r_index][win_counter];
      im_prev      = (Ipp16s*)pBlock->im_short[ind][pBlockCom->prev_f_r_index][win_counter];

      r_prevScaleFactor =
        pBlock->rScaleFactorShort[ind][pBlockCom->prev_f_r_index][win_counter];

      r_prev_prev  = (Ipp16s*)pBlock->r_short[ind][pBlockCom->prev_prev_f_r_index][win_counter];
      re_prev_prev = (Ipp16s*)pBlock->re_short[ind][pBlockCom->prev_prev_f_r_index][win_counter];
      im_prev_prev = (Ipp16s*)pBlock->im_short[ind][pBlockCom->prev_prev_f_r_index][win_counter];

      r_prev_prevScaleFactor =
        pBlock->rScaleFactorShort[ind][pBlockCom->prev_prev_f_r_index][win_counter];

      /* Calculate the unpredictebility measure c(w)                */
      /* Some transformations:                                      */
      /* re((2*r_prev-r_prev_prev)*exp(-j(2*f_prev-f_prev_prev))) = */
      /* (2*r_prev-r_prev_prev)*                                    */
      /* (2*im_prev_prev*re_prev*im_prev +                          */
      /* re_prev_prev*(re_prev*re_prev-im_prev*im_prev))            */
      /*                                                            */
      /* im((2*r_prev-r_prev_prev)*exp(-j(2*f_prev-f_prev_prev))) = */
      /* (2*r_prev-r_prev_prev) *                                   */
      /* (2*re_prev_prev*re_prev*im_prev -                          */
      /* im_prev_prev*(re_prev*re_prev-im_prev*im_prev))            */
      /*                                                            */
      /* where re_prev_prev = cos(prev_prev_f),                     */
      /*       im_prev_prev = sin(prev_prev_f),                     */
      /*       re_prev = cos(prev_prev_f),                          */
      /*       im_prev = sin(prev_prev_f)                           */

      /* r_pred = (2*r_prev-r_prev_prev) */
      r_predScaleFactor = r_prevScaleFactor + 1;
      if (r_prev_prevScaleFactor > r_predScaleFactor) {
        shift = r_prev_prevScaleFactor - r_predScaleFactor;
        if (shift > 16) shift = 16;
        ippsRShiftC_16s(r_prev, shift, tmp0, pBlockCom->iblen_short);
        ippsSub_16s_Sfs(r_prev_prev, tmp0, r_pred, pBlockCom->iblen_short, 1);
        r_predScaleFactor = r_prev_prevScaleFactor + 1;
      } else if (r_prev_prevScaleFactor < r_predScaleFactor) {
        shift = r_predScaleFactor - r_prev_prevScaleFactor;
        if (shift > 16) shift = 16;
        ippsRShiftC_16s(r_prev_prev, shift, tmp0, pBlockCom->iblen_short);
        ippsSub_16s_Sfs(tmp0, r_prev, r_pred, pBlockCom->iblen_short, 1);
        r_predScaleFactor++;
      } else {
        ippsSub_16s_Sfs(r_prev_prev, r_prev, r_pred, pBlockCom->iblen_short, 1);
        r_predScaleFactor++;
      }

      /* tmp1 = 2*re_prev*im_prev (in Q14) */
      ippsMul_16s_Sfs(re_prev, im_prev, tmp1, pBlockCom->iblen_short, 15);

      /* tmp2 = re_prev*re_prev-im_prev*im_prev (in Q14)*/
      ippsMul_16s_Sfs(re_prev, re_prev, tmp, pBlockCom->iblen_short, 15);
      ippsMul_16s_Sfs(im_prev, im_prev, tmp2, pBlockCom->iblen_short, 15);
      ippsSub_16s_ISfs(tmp, tmp2,  pBlockCom->iblen_short, 1);

      /* im_prev_prev * tmp1 + re_prev_prev * tmp2 (in Q13)*/
      ippsMul_16s_Sfs(im_prev_prev, tmp1, re_pred, pBlockCom->iblen_short, 15);
      ippsMul_16s_Sfs(re_prev_prev, tmp2, tmp, pBlockCom->iblen_short, 15);
      ippsAdd_16s_ISfs(tmp, re_pred, pBlockCom->iblen_short, 1);

      /* re_prev_prev * tmp1 - im_prev_prev * tmp2  (in Q13)*/
      ippsMul_16s_Sfs(re_prev_prev, tmp1, im_pred, pBlockCom->iblen_short, 15);
      ippsMul_16s_Sfs(im_prev_prev, tmp2, tmp, pBlockCom->iblen_short, 15);
      ippsSub_16s_ISfs(tmp, im_pred, pBlockCom->iblen_short, 1);

      ippsAbs_16s(r_pred, denum,  pBlockCom->iblen_short);

      /* denumScaleFactor = (shift0 == 0) ? r_predScaleFactor + 1 : rScaleFactor + 1 */
      if (r_predScaleFactor > rScaleFactor) {
        shift0 = 0;
        shift1 = r_predScaleFactor - rScaleFactor;
        if (shift1 > 16) shift1 = 16;
        ippsRShiftC_16s(r, shift1, tmp0, pBlockCom->iblen_short);
        ippsAdd_16s_ISfs(tmp0, denum, pBlockCom->iblen_short, 1);
      } else if (r_predScaleFactor < rScaleFactor) {
        shift0 = rScaleFactor - r_predScaleFactor;
        shift1 = 0;
        if (shift0 > 16) shift0 = 16;
        ippsRShiftC_16s(denum, shift0, tmp0, pBlockCom->iblen_short);
        ippsAdd_16s_Sfs(r, tmp0, denum, pBlockCom->iblen_short, 1);
      } else {
        shift0 = 0;
        shift1 = 0;
        ippsAdd_16s_ISfs(r, denum, pBlockCom->iblen_short, 1);
      }

      /* tmp0 in Q15 */
      ippsDiv_16s_Sfs(denum, r_pred, tmp0, pBlockCom->iblen_short, -14 + shift0);

      /* tmp1 in Q15 */
      ippsDiv_16s_Sfs(denum, r, tmp1, pBlockCom->iblen_short, -14 + shift1);

      /* tmp2 in Q13 */
      ippsMul_16s_Sfs(tmp0, re_pred, tmp2, pBlockCom->iblen_short, 15);
      /* tmp3 in Q13 */
      ippsMul_16s_Sfs(tmp0, im_pred, tmp3, pBlockCom->iblen_short, 15);
      /* tmp4 in Q13 */
      ippsMul_16s_Sfs(tmp1, re, tmp4, pBlockCom->iblen_short, 17);
      /* tmp5 in Q13 */
      ippsMul_16s_Sfs(tmp1, im, tmp5, pBlockCom->iblen_short, 17);
      /* tmp0 in Q12 */
      ippsSub_16s_Sfs(tmp2, tmp4, tmp0, pBlockCom->iblen_short, 1);
      /* tmp1 in Q12 */
      ippsSub_16s_Sfs(tmp3, tmp5, tmp1, pBlockCom->iblen_short, 1);
      /* c_w in Q15 */
      ippsMagnitude_16s_Sfs(tmp0, tmp1, c_w, pBlockCom->iblen_short, -3);

      rsqr = rsqr_short;

      ippsMul_16s32s_Sfs((Ipp16s*)r, (Ipp16s*)r, rsqr, pBlockCom->iblen_short, 0);
      rsqr_shortScale = 2 * rScaleFactor;

      for (b = 0; b < num_ptt_short; b++) {
        Ipp32s *tmp_rsqr = &rsqr[pBlockCom->shortWindow->w_low[b]];
        Ipp16s *tmp_c_w = (Ipp16s*)&c_w[pBlockCom->shortWindow->w_low[b]];
        Ipp32s len = pBlockCom->shortWindow->w_width[b];

        ippsSum_32s_Sfs(tmp_rsqr, len, &e_b[b], pBlockCom->shortScale - 1);
        ippsDotProd_16s32s32s_Sfs(tmp_c_w, tmp_rsqr, len, &c_b[b],
                                  pBlockCom->shortScale + 14);
      }

      for (b = 0; b < num_ptt_short; b++) {
        Ipp16s *tmp_ptr = (Ipp16s*)pBlockCom->sprdngf_short +
                                  b * num_ptt_short;

        ippsDotProd_16s32s32s_Sfs(tmp_ptr, e_b, num_ptt_short, &ecb[b], 15);
        ippsDotProd_16s32s32s_Sfs(tmp_ptr, c_b, num_ptt_short, &ct[b], 15);
      }

      ippsMulC_32s_Sfs(ecb, 20219, tmp_ecb, num_ptt_short, 21);
      ippsMulC_32s_Sfs(ct, 17131, tmp_ct, num_ptt_short, 15);

      ippsAdd_32s_Sfs(tmp_ct, tmp_ecb, nb, num_ptt_short, 0);
      ippsMulC_32s_Sfs(ecb, 16462, ecb_h_limit, num_ptt_short, 16);
      ippsMulC_32s_Sfs(ecb, 16619, ecb_l_limit, num_ptt_short, 20);
      ippsMaxEvery_32s_I(ecb_l_limit, nb, num_ptt_short);
      ippsMinEvery_32s_I(ecb_h_limit, nb, num_ptt_short);

      for (sb = 0; sb < pBlockCom->num_sfb_short; sb++) {
        Ipp32s start = pBlockCom->aacenc_p2sb_s[sb].bu;
        Ipp32s end = pBlockCom->aacenc_p2sb_s[sb].bo;

        epart[sb] = (Ipp32s)((((Ipp64s)pBlockCom->aacenc_p2sb_s[sb].w1 * e_b[start]) >> 32) +
                             (((Ipp64s)pBlockCom->aacenc_p2sb_s[sb].w2 * e_b[end]) >> 32));

        npart[sb] = (Ipp32s)((((Ipp64s)pBlockCom->aacenc_p2sb_s[sb].w1 * nb[start]) >> 32) +
                             (((Ipp64s)pBlockCom->aacenc_p2sb_s[sb].w2 * nb[end]) >> 32));

        for (b = start + 1; b < end; b++) {
          epart[sb] += (e_b[b] >> 2);
          npart[sb] += (nb[b] >> 2);
        }
      }

      smr = (Ipp32s*)pBlock->smr_short[pBlockCom->nb_curr_index] +
        pBlockCom->num_sfb_short * win_counter;

      ippsDiv_32s_Sfs(epart, npart, smr, pBlockCom->num_sfb_short, -21);
    }
  }
}

/****************************************************************************/

AACStatus aaciencInitPsychoacousticCom(sPsychoacousticBlockCom* pBlock,
                                       Ipp8u* mem,
                                       Ipp32s sf_index,
                                       Ipp32s ns_mode,
                                       Ipp32s *size_all)
{
  Ipp32s i;
  Ipp32s max_len;
  Ipp32s num_ptt, b, bb;
  Ipp8u  *pBufInit;
  Ipp16s *bval;
  Ipp16s *sprdngf;
  Ipp32s jj;
  Ipp32s sizeSpecLong, sizeInit, sizeWork;
  Ipp32s sizeSpecShort, sizeInitShort, sizeWorkShort;

  if (pBlock) {
    pBlock->iblen_long  = 1024;
    pBlock->iblen_short = 128;

    pBlock->nb_curr_index = 1;
    pBlock->nb_prev_index = 0;

    pBlock->aacenc_p2sb_l = aacienc_p2sb_l[sf_index];
    pBlock->aacenc_p2sb_s = aacienc_p2sb_s[sf_index];
    pBlock->sfb_offset_long  = sfb_tables[sf_index].sfb_offset_long_window;
    pBlock->sfb_offset_short = sfb_tables[sf_index].sfb_offset_short_window;
    pBlock->num_sfb_long = sfb_tables[sf_index].num_sfb_long_window;
    pBlock->num_sfb_short = sfb_tables[sf_index].num_sfb_short_window;

    pBlock->longWindow    = &aacienc_psy_partition_tables_long[sf_index];
    pBlock->shortWindow   = &aacienc_psy_partition_tables_short[sf_index];


    num_ptt = pBlock->longWindow->num_ptt;
    bval = (Ipp16s*)pBlock->longWindow->bval;
    sprdngf = (Ipp16s*)pBlock->sprdngf_long;

    for (jj = 0; jj < 2; jj++) {

      for (b = 0; b < num_ptt; b++) {
        Ipp16s *tmp_ptr = sprdngf + b * num_ptt;
        Ipp32s tmp = 0;
        Ipp32s scalef = -15;
        Ipp16s src2 = bval[b];

        for (bb = 0; bb < num_ptt; bb++) {
          ippsSpread_16s_Sfs(bval[bb], src2, -10, tmp_ptr + bb);
          tmp += tmp_ptr[bb];
        }

        while (tmp >= 32768) {
          scalef += 1;
          tmp >>= 1;
        }

        ippsDivC_16s_ISfs((Ipp16s)tmp, tmp_ptr, num_ptt, scalef);
      }

      num_ptt = pBlock->shortWindow->num_ptt;
      bval = (Ipp16s*)pBlock->shortWindow->bval;
      sprdngf = (Ipp16s*)pBlock->sprdngf_short;
    }

    max_len = 0;
    for (i = 0; i < pBlock->longWindow->num_ptt; i++) {
      Ipp32s len = pBlock->longWindow->w_width[i];
      if (len > max_len) max_len = len;
    }

    pBlock->longScale = 0;
    while (max_len > (1 << pBlock->longScale)) {
      pBlock->longScale++;
    }
  }

  if (ippsFFTGetSize_R_16s(11, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast,
                           &sizeSpecLong, &sizeInit, &sizeWork) != ippStsOk) {
    return AAC_ALLOC;
  }

  if (ippsFFTGetSize_R_16s(8, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast,
                           &sizeSpecShort, &sizeInitShort, &sizeWorkShort) != ippStsOk) {
    return AAC_ALLOC;
  }

  if (sizeInit < sizeInitShort)
    sizeInit = sizeInitShort;

  if (sizeWork < sizeWorkShort)
    sizeWork = sizeWorkShort;

  *size_all = sizeSpecLong + sizeSpecShort + sizeWork + sizeInit;

  if (pBlock) {
    pBlock->pBuffer = mem + sizeSpecLong + sizeSpecShort;
    pBufInit = pBlock->pBuffer + sizeWork;

    if (ippsFFTInit_R_16s(&(pBlock->pFFTSpecLong), 11, IPP_FFT_NODIV_BY_ANY,
                          ippAlgHintFast, mem, pBufInit) != ippStsOk) {
      return AAC_ALLOC;
    }

    if (ippsFFTInit_R_16s(&(pBlock->pFFTSpecLong), 8, IPP_FFT_NODIV_BY_ANY,
                          ippAlgHintFast, mem + sizeSpecLong, pBufInit) != ippStsOk) {
      return AAC_ALLOC;
    }

    pBlock->ns_mode = ns_mode;

    if (pBlock->ns_mode) {
      max_len = 0;
      for (i = 0; i < pBlock->shortWindow->num_ptt; i++) {
        Ipp32s len = pBlock->shortWindow->w_width[i];
        if (len > max_len) max_len = len;
      }

      pBlock->shortScale = 0;
      while (max_len > (1 << pBlock->shortScale)) {
        pBlock->shortScale++;
      }

      max_len = 0;
      for (i = 0; i < pBlock->num_sfb_long; i++) {
        Ipp32s len = pBlock->sfb_offset_long[i + 1] - pBlock->sfb_offset_long[i];
        pBlock->sfb_width_long[i] = len;
        if (len > max_len) max_len = len;
      }

      pBlock->sfb_width_longScale = 0;
      while (max_len > (1 << pBlock->sfb_width_longScale)) {
        pBlock->sfb_width_longScale++;
      }

      max_len = 0;
      for (i = 0; i < pBlock->num_sfb_short; i++) {
        Ipp32s len = pBlock->sfb_offset_short[i + 1] - pBlock->sfb_offset_short[i];
        pBlock->sfb_width_short[i] = len;
        if (len > max_len) max_len = len;
      }

      pBlock->sfb_width_shortScale = 0;
      while (max_len > (1 << pBlock->sfb_width_shortScale)) {
        pBlock->sfb_width_shortScale++;
      }

      {
        Ipp16u tmp_buf[((MAX_PPT_LONG > MAX_PPT_SHORT) ? MAX_PPT_LONG : MAX_PPT_SHORT)];

        for (i = 0; i < pBlock->longWindow->num_ptt; i++) {
          tmp_buf[i] = pBlock->longWindow->w_width[i];
        }

        ippsDivCRev_16u_I(0x8000, tmp_buf, pBlock->longWindow->num_ptt);

        for (i = 0; i < pBlock->longWindow->num_ptt; i++) {
          pBlock->w_width_long_inv[i] = tmp_buf[i];
        }

        for (i = 0; i < pBlock->shortWindow->num_ptt; i++) {
          tmp_buf[i] = pBlock->shortWindow->w_width[i];
        }

        ippsDivCRev_16u_I(0x8000, tmp_buf, pBlock->shortWindow->num_ptt);

        for (i = 0; i < pBlock->shortWindow->num_ptt; i++) {
          pBlock->w_width_short_inv[i] = tmp_buf[i];
        }
      }
    }
  }
  return AAC_OK;
}

/****************************************************************************/

void aaciencInitPsychoacoustic(sPsychoacousticBlock* pBlock)
{
  Ipp32s i, j, k;

  pBlock->block_type = ONLY_LONG_SEQUENCE;
  pBlock->desired_block_type = ONLY_LONG_SEQUENCE;
  pBlock->next_frame_PE = 0;
  pBlock->stereo_mode[0] = pBlock->stereo_mode[1] = AAC_LR_STEREO;
  pBlock->ms_coef[0] = pBlock->ms_coef[1] = 8;

  for (k = 0; k < 2; k++) {
    for (j = 0; j < 3; j++) {
      ippsSet_16s(1, pBlock->r[k][j], 1024);
      ippsSet_16s(1, pBlock->re[k][j], 1024);
      ippsSet_16s(0, pBlock->im[k][j], 1024);
      pBlock->rScaleFactor[k][j] = 0;
      //pBlock->ScaleFactor[k][j] = 0;
    }
    ippsSet_32s(0x7FFFFFFF, pBlock->nb_long[k][0], MAX_PPT_LONG);
    ippsSet_32s(0x7FFFFFFF, pBlock->nb_long[k][1], MAX_PPT_LONG);
    pBlock->nb_longScaleFactor[k] = 0x7FFFFFF;
  }

  for (k = 0; k < 2; k++) {
    for (j = 0; j < 3; j++) {
      for (i = 0; i < 8; i++) {
        ippsSet_16s(1, pBlock->r_short[k][j][i], 128);
        ippsSet_16s(1, pBlock->re_short[k][j][i], 128);
        ippsSet_16s(0, pBlock->im_short[k][j][i], 128);
      }
    }
  }

  for (k = 0; k < 2; k++) {
    ippsSet_32s(0, pBlock->smr_long[k], MAX_SFB);
    ippsSet_32s(0, pBlock->smr_short[k], MAX_SFB);
  }
}

/****************************************************************************/

void aaciencFreePsychoacousticCom(sPsychoacousticBlockCom* pBlock)
{
  if (pBlock) {
    if (pBlock->pFFTSpecShort)
      ippsFFTFree_R_16s(pBlock->pFFTSpecShort);

    if (pBlock->pFFTSpecLong)
      ippsFFTFree_R_16s(pBlock->pFFTSpecLong);

    if (pBlock->pBuffer)
      ippsFree(pBlock->pBuffer);
  }
}

/****************************************************************************/

static void aaciencPsy_block_def(sPsychoacousticBlock* pBlock,
                                 sPsychoacousticBlockCom* pBlockCom,
                                 Ipp32s *ms_pwr,
                                 Ipp32s *ms_pwr_Scalef,
                                 Ipp32s *PE,
                                 Ipp32s ch,
                                 Ipp32s ind)
{
  Ipp32s  s_en[8];
  Ipp32s  min, max;

  pBlock->curr_frame_PE = pBlock->next_frame_PE;

  aaciencPsy_long_window(pBlock, pBlockCom, ms_pwr, ms_pwr_Scalef, PE, ch, ind);
  aaciencPsy_short_window(pBlock, pBlockCom, s_en, ch, ind);

  ippsMinMax_32s(s_en, 8, &min, &max);

  /* part 1 */
  if (pBlock->next_frame_PE > 5800) {
    pBlock->next_desired_block_type[ind] = EIGHT_SHORT_SEQUENCE;
  } else if (max > 25 * min) {
    pBlock->next_desired_block_type[ind] = EIGHT_SHORT_SEQUENCE;
  } else if ((max > 10 * min) && (PE[0] > 1900)) {
    pBlock->next_desired_block_type[ind] = EIGHT_SHORT_SEQUENCE;
  } else {
    pBlock->next_desired_block_type[ind] = ONLY_LONG_SEQUENCE;
  }
}

/****************************************************************************/

void aaciencPsychoacoustic(sPsychoacousticBlock** pBlock,
                           sPsychoacousticBlockCom* pBlockCom,
                           Ipp32s ms_thr,
                           Ipp32s numCh)
{
  Ipp32s *stereo_mode = &pBlock[0]->stereo_mode[pBlockCom->nb_curr_index];
  Ipp32s coef, abs_coef, ms_pwr[2], ms_pwr_Scalef[2], PE[2][2];
  Ipp32s ch, ms, shift;

  for (ch = 0; ch < numCh; ch++) {
    aaciencPsy_block_def(pBlock[ch], pBlockCom, &ms_pwr[ch],
                         &ms_pwr_Scalef[ch], &PE[0][ch], ch, 0);
  }

  if (stereo_mode[0] == AAC_MS_STEREO || stereo_mode[0] == AAC_JOINT_STEREO) {
    Ipp16s bufL[2][1024];
    Ipp16s bufR[2][1024];
    Ipp16s *ptrL, *ptrR;
    Ipp32s k, w;

    for (w = 0; w < 2; w++) {
      ptrL = pBlockCom->input_data[0][w];
      ptrR = pBlockCom->input_data[1][w];

      for (k = 0; k < 1024; k++) {
        bufL[w][k] = (Ipp16s)(((Ipp32s)ptrL[k] + (Ipp32s)ptrR[k]) >> 1);
        bufR[w][k] = (Ipp16s)(((Ipp32s)ptrL[k] - (Ipp32s)ptrR[k]) >> 1);
      }

      pBlockCom->input_data[0][w] = bufL[w];
      pBlockCom->input_data[1][w] = bufR[w];
    }

    for (ch = 0; ch < 2; ch++) {
      aaciencPsy_block_def(pBlock[ch], pBlockCom, &ms_pwr[ch],
                           &ms_pwr_Scalef[ch], &PE[1][ch], ch, 1);
    }

    for (k = 0; k < 2; k++) {
      if (pBlock[0]->next_desired_block_type[k] !=
        pBlock[1]->next_desired_block_type[k]) {
          pBlock[0]->next_desired_block_type[k] =
            pBlock[1]->next_desired_block_type[k] = EIGHT_SHORT_SEQUENCE;
        }
    }

    if (ms_pwr_Scalef[0] > ms_pwr_Scalef[1]) {
      shift = ms_pwr_Scalef[0] - ms_pwr_Scalef[1];
      if (shift > 31) shift = 31;
      ms_pwr[1] >>= shift;
    } else {
      shift = ms_pwr_Scalef[1] - ms_pwr_Scalef[0];
      if (shift > 31) shift = 31;
      ms_pwr[0] >>= shift;
    }

    coef = ms_pwr[0] + ms_pwr[1]; /* coef is less than 2 * 1024 * 32768 */
    if (coef > 0) {
      coef = (ms_pwr[0] * 16) / coef; /* Q4 */
    } else {
      coef = 8;
    }

    abs_coef = coef - 8;
    if (abs_coef < 0) abs_coef = -abs_coef;

    if (stereo_mode[0] == AAC_JOINT_STEREO) {
      if (((PE[1][0] + PE[1][1]) < ((11 * (PE[0][0] + PE[0][1])) >> 4)) ||
           abs_coef > ms_thr)
        stereo_mode[0] = AAC_MS_STEREO;
      else
        stereo_mode[0] = AAC_LR_STEREO;
    }
    pBlock[0]->ms_coef[pBlockCom->nb_curr_index] = coef;
  }

  ms = stereo_mode[0] == AAC_MS_STEREO ? 1 : 0;

  for (ch = 0; ch < numCh; ch++) {
    Ipp32s next_desired_block_type = pBlock[ch]->next_desired_block_type[ms];

    /* part 2 */
    if ((pBlock[ch]->block_type == EIGHT_SHORT_SEQUENCE) ||
      (pBlock[ch]->block_type == LONG_START_SEQUENCE)) {
        if ((pBlock[ch]->desired_block_type == ONLY_LONG_SEQUENCE) &&
          (next_desired_block_type == ONLY_LONG_SEQUENCE)) {
            pBlock[ch]->block_type = LONG_STOP_SEQUENCE;
          } else {
            pBlock[ch]->block_type = EIGHT_SHORT_SEQUENCE;
          }
      } else if (next_desired_block_type == EIGHT_SHORT_SEQUENCE) {
        pBlock[ch]->block_type = LONG_START_SEQUENCE;
      } else {
        pBlock[ch]->block_type = ONLY_LONG_SEQUENCE;
      }
      pBlock[ch]->desired_block_type = next_desired_block_type;
      pBlock[ch]->next_frame_PE = PE[ms][ch];
  }
}

#endif //UMC_ENABLE_AAC_INT_AUDIO_ENCODER

